/*
 * write_cpp.c
 *
 *  Created on: 2012/08/01
 *      Author: owner
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "sqlite3.h"
#include "db_def.h"
#include "typedef.h"
#include "core.h"
#include "Id.h"
#include "../../CCore/parser/cpp/cppdef.h"
#include "../../CCore/parser/coredef.h"
#include "../../CCore/table/core_table.h"

/*TBL_CPPDIRECTIVEINFO*/
static INT insertCppDirectiveInfo(sqlite3 *db, AST tuIdx) {
	INT rc = 0;
	sqlite3_stmt * stmt;
	const char *zTail;
	PSZ sql_insert = NULL;
	BOOL bIsErr = FALSE;

	AST max = 0;
	AST i = 0;
	U2 macroKind = 0;

	rc = sqlite3_exec(db, "begin;", 0, 0, 0);
	if (rc != SQLITE_OK) {
		return rc;
	}

	max = stCoreDirectiveInfoAccess.getMax();

	sql_insert = sqlite3_mprintf("INSERT INTO %q VALUES(?,?,?,?,?,?,?,?,?);",
			TBL_CPPDIRECTIVEINFO);
	rc = sqlite3_prepare(db, sql_insert, -1, &stmt, &zTail);
	if (rc != SQLITE_OK || stmt == NULL ) {
		if (sql_insert != NULL ) {
			sqlite3_free(sql_insert);
		}
		if (stmt != NULL ) {
			sqlite3_finalize(stmt);
		}
		return COEXIT_ERROR;
	}

	for (i = 1; i <= max; i++) {

		sqlite3_bind_int(stmt, CPP_UNIT_INDEX, tuIdx);
		sqlite3_bind_int(stmt, CPP_TABLE_INDEX, i);

		macroKind = stCoreDirectiveInfoAccess.kind.get(i);
		sqlite3_bind_int(stmt, DIRECTIVE_DIRECTIVE_KIND, macroKind);

		sqlite3_bind_int(stmt, DIRECTIVE_PARAM_IDX, 0);
		sqlite3_bind_text(stmt, DIRECTIVE_PARAM_STR, "", -1, SQLITE_STATIC );
		sqlite3_bind_int(stmt, DIRECTIVE_PARAM_S4, 0);
		sqlite3_bind_int(stmt, DIRECTIVE_RESULT_BOOL, 0);
		sqlite3_bind_int(stmt, DIRECTIVE_RESULT_IDX, 0);
		switch (macroKind) {
		case CPPDEF_DEF:
		case CPPDEF_UNDEF:
		case CPPDEF_INC:
			sqlite3_bind_int(stmt, DIRECTIVE_RESULT_IDX,
					stCoreDirectiveInfoAccess.idx_result.get(i));
			sqlite3_bind_text(stmt, DIRECTIVE_PARAM_STR,
					stCoreDirectiveInfoAccess.str_param.get(i), -1,
					SQLITE_STATIC );
			break;
		case CPPDEF_IF:
		case CPPDEF_ELIF:
			sqlite3_bind_int(stmt, DIRECTIVE_PARAM_IDX,
					stCoreDirectiveInfoAccess.idx_param.get(i));
			sqlite3_bind_int(stmt, DIRECTIVE_RESULT_BOOL,
					stCoreDirectiveInfoAccess.bool_result.get(i));
			break;
		case CPPDEF_ELSE:
			sqlite3_bind_int(stmt, DIRECTIVE_RESULT_BOOL,
					stCoreDirectiveInfoAccess.bool_result.get(i));
			break;
		case CPPDEF_IFDEF:
		case CPPDEF_IFNDEF:
			sqlite3_bind_text(stmt, DIRECTIVE_PARAM_STR,
					stCoreDirectiveInfoAccess.str_param.get(i), -1,
					SQLITE_STATIC );
			sqlite3_bind_int(stmt, DIRECTIVE_RESULT_BOOL,
					stCoreDirectiveInfoAccess.bool_result.get(i));
			break;
		case CPPDEF_LINE:
			sqlite3_bind_int(stmt, DIRECTIVE_PARAM_S4,
					stCoreDirectiveInfoAccess.s4_param.get(i));
			sqlite3_bind_text(stmt, DIRECTIVE_PARAM_STR,
					stCoreDirectiveInfoAccess.str_param.get(i), -1,
					SQLITE_STATIC );
			break;
		case CPPDEF_ERROR:
		case CPPDEF_PRAGMA:
			sqlite3_bind_text(stmt, DIRECTIVE_PARAM_STR,
					stCoreDirectiveInfoAccess.str_param.get(i), -1,
					SQLITE_STATIC );
			break;
		default:
			break;
		}

		sqlite3_bind_int(stmt, DIRECTIVE_CODE_SCOPE,
				stCoreDirectiveInfoAccess.locScope.get(i));

		rc = sqlite3_step(stmt);
		if (rc != SQLITE_DONE) {
			bIsErr = TRUE;
			printf("%s", sqlite3_errmsg(db));
			break;
		}
		sqlite3_reset(stmt);
	}

	if (bIsErr) {
		rc = sqlite3_exec(db, "rollback;", 0, 0, 0);
	} else {
		rc = sqlite3_exec(db, "commit;", 0, 0, 0);
	}

	if (sql_insert != NULL ) {
		sqlite3_free(sql_insert);
	}
	if (stmt != NULL ) {
		rc = sqlite3_finalize(stmt);
	}
	return rc;
}

/*TBL_CPPMACRODEFINFO*/
static INT insertCppMacroDefInfo(sqlite3 *db, AST tuIdx) {
	INT rc = 0;
	sqlite3_stmt * stmt;
	const char *zTail;
	PSZ sql_insert = NULL;
	BOOL bIsErr = FALSE;

	AST max = 0;
	AST i = 0;

	rc = sqlite3_exec(db, "begin;", 0, 0, 0);
	if (rc != SQLITE_OK) {
		return rc;
	}

	max = stCoreMacroDefInfoAccess.getMax();

	sql_insert = sqlite3_mprintf("INSERT INTO %q VALUES(?,?,?,?,?,?,?,?,?,?);",
			TBL_CPPMACRODEFINFO);
	rc = sqlite3_prepare(db, sql_insert, -1, &stmt, &zTail);
	if (rc != SQLITE_OK || stmt == NULL ) {
		if (sql_insert != NULL ) {
			sqlite3_free(sql_insert);
		}
		if (stmt != NULL ) {
			sqlite3_finalize(stmt);
		}
		return COEXIT_ERROR;
	}

	for (i = 1; i <= max; i++) {

		sqlite3_bind_int(stmt, CPP_UNIT_INDEX, tuIdx);
		sqlite3_bind_int(stmt, CPP_TABLE_INDEX, i);

		sqlite3_bind_int(stmt, MACRODEF_MACRO_KIND,
				stCoreMacroDefInfoAccess.macroKind.get(i));

		sqlite3_bind_int(stmt, MACRODEF_PARAMETER_NUMBER,
				stCoreMacroDefInfoAccess.paramNum.get(i));

		sqlite3_bind_int(stmt, MACRODEF_IS_VALID,
				stCoreMacroDefInfoAccess.bValid.get(i));

		sqlite3_bind_int(stmt, MACRODEF_HAS_VARIABLE_PARAMETERS,
				stCoreMacroDefInfoAccess.bVariableParam.get(i));

		sqlite3_bind_int(stmt, MACRODEF_FIRST_TOKEN_INFO,
				stCoreMacroDefInfoAccess.startReplaceEle.get(i));

		sqlite3_bind_int(stmt, MACRODEF_LAST_TOKEN_INFO,
				stCoreMacroDefInfoAccess.endReplaceEle.get(i));

		sqlite3_bind_int(stmt, MACRODEF_DIRECTIVE_INFO,
				stCoreMacroDefInfoAccess.directiveInfo.get(i));

		sqlite3_bind_text(stmt, MACRODEF_MACRO_NAME,
				stCoreMacroDefInfoAccess.macroName.get(i), -1, SQLITE_STATIC );

		rc = sqlite3_step(stmt);
		if (rc != SQLITE_DONE) {
			bIsErr = TRUE;
			printf("%s", sqlite3_errmsg(db));
			break;
		}
		sqlite3_reset(stmt);
	}

	if (bIsErr) {
		rc = sqlite3_exec(db, "rollback;", 0, 0, 0);
	} else {
		rc = sqlite3_exec(db, "commit;", 0, 0, 0);
	}

	if (sql_insert != NULL ) {
		sqlite3_free(sql_insert);
	}
	if (stmt != NULL ) {
		rc = sqlite3_finalize(stmt);
	}
	return rc;
}

/*TBL_CPPDEFREPINFO*/
static INT insertCppDefRepInfo(sqlite3 *db, AST tuIdx) {
	INT rc = 0;
	sqlite3_stmt * stmt;
	const char *zTail;
	PSZ sql_insert = NULL;
	BOOL bIsErr = FALSE;

	AST max = 0;
	AST i = 0;

	rc = sqlite3_exec(db, "begin;", 0, 0, 0);
	if (rc != SQLITE_OK) {
		return rc;
	}

	max = stCoreDefRepInfoAccess.getMax();

	sql_insert = sqlite3_mprintf("INSERT INTO %q VALUES(?,?,?,?,?,?,?,?);",
			TBL_CPPDEFREPINFO);
	rc = sqlite3_prepare(db, sql_insert, -1, &stmt, &zTail);
	if (rc != SQLITE_OK || stmt == NULL ) {
		if (sql_insert != NULL ) {
			sqlite3_free(sql_insert);
		}
		if (stmt != NULL ) {
			sqlite3_finalize(stmt);
		}
		return COEXIT_ERROR;
	}

	for (i = 1; i <= max; i++) {

		sqlite3_bind_int(stmt, CPP_UNIT_INDEX, tuIdx);
		sqlite3_bind_int(stmt, CPP_TABLE_INDEX, i);

		sqlite3_bind_int(stmt, DEFREP_INDEX_COUNTER,
				stCoreDefRepInfoAccess.index.get(i));

		sqlite3_bind_int(stmt, DEFREP_PARAM_KIND,
				stCoreDefRepInfoAccess.kind.get(i));

		sqlite3_bind_int(stmt, DEFREP_PARAM_INDEX,
				stCoreDefRepInfoAccess.paramIdx.get(i));

		sqlite3_bind_text(stmt, DEFREP_TOKEN_LABEL,
				stCoreDefRepInfoAccess.name.get(i), -1, SQLITE_STATIC );

		sqlite3_bind_int(stmt, DEFREP_TOKEN_KIND,
				stCoreDefRepInfoAccess.ppTokenKind.get(i));

		sqlite3_bind_int(stmt, DEFREP_CODE_SCOPE_INFO,
				stCoreDefRepInfoAccess.location.get(i));

		rc = sqlite3_step(stmt);
		if (rc != SQLITE_DONE) {
			bIsErr = TRUE;
			printf("%s", sqlite3_errmsg(db));
			break;
		}
		sqlite3_reset(stmt);
	}

	if (bIsErr) {
		rc = sqlite3_exec(db, "rollback;", 0, 0, 0);
	} else {
		rc = sqlite3_exec(db, "commit;", 0, 0, 0);
	}

	if (sql_insert != NULL ) {
		sqlite3_free(sql_insert);
	}
	if (stmt != NULL ) {
		rc = sqlite3_finalize(stmt);
	}
	return rc;
}

/*TBL_CPPPPCONDITION*/
static INT insertCppPPCondition(sqlite3 *db, AST tuIdx) {
	INT rc = 0;
	sqlite3_stmt * stmt;
	const char *zTail;
	PSZ sql_insert = NULL;
	BOOL bIsErr = FALSE;

	AST max = 0;
	AST i = 0;
	U4 opKind = 0;

	rc = sqlite3_exec(db, "begin;", 0, 0, 0);
	if (rc != SQLITE_OK) {
		return rc;
	}

	max = stCorePPConditionAccess.getMax();

	sql_insert = sqlite3_mprintf("INSERT INTO %q VALUES(?,?,?,?,?,?,?,?,?,?);",
			TBL_CPPPPCONDITION);
	rc = sqlite3_prepare(db, sql_insert, -1, &stmt, &zTail);
	if (rc != SQLITE_OK || stmt == NULL ) {
		if (sql_insert != NULL ) {
			sqlite3_free(sql_insert);
		}
		if (stmt != NULL ) {
			sqlite3_finalize(stmt);
		}
		return COEXIT_ERROR;
	}

	for (i = 1; i <= max; i++) {

		sqlite3_bind_int(stmt, CPP_UNIT_INDEX, tuIdx);
		sqlite3_bind_int(stmt, CPP_TABLE_INDEX, i);

		opKind = stCorePPConditionAccess.OpKind.get(i);
		sqlite3_bind_int(stmt, CPPCOND_OPER_KIND, opKind);

		sqlite3_bind_double(stmt, CPPCOND_VALUEOF_DOUBLE, 0);
		sqlite3_bind_int64(stmt, CPPCOND_VALUEOF_UNSIGNED, 0);
		sqlite3_bind_int(stmt, CPPCOND_VALUEOF_SIGNED, 0);
		switch (opKind) {
		case xPPTOKEN_DOUBLE:
			sqlite3_bind_double(stmt, CPPCOND_VALUEOF_DOUBLE,
					stCorePPConditionAccess.dbValue.get(i));
			break;

		case xPPTOKEN_ULONG:
			sqlite3_bind_int64(stmt, CPPCOND_VALUEOF_UNSIGNED,
					stCorePPConditionAccess.u4Value.get(i));
			break;

		case xPPTOKEN_LONG:
			sqlite3_bind_int(stmt, CPPCOND_VALUEOF_SIGNED,
					stCorePPConditionAccess.s4Value.get(i));
			break;

		default:
			break;
		}

		sqlite3_bind_int(stmt, CPPCOND_LEFT_NODE_INFO,
				stCorePPConditionAccess.leftNode.get(i));

		sqlite3_bind_int(stmt, CPPCOND_RIGHT_NODE_INFO,
				stCorePPConditionAccess.rightNode.get(i));

		sqlite3_bind_int(stmt, CPPCOND_CODE_SCOPE_INFO,
				stCorePPConditionAccess.locScp.get(i));

		sqlite3_bind_int(stmt, CPPCOND_NODE_KIND,
				stCorePPConditionAccess.nodeKind.get(i));

		rc = sqlite3_step(stmt);
		if (rc != SQLITE_DONE) {
			bIsErr = TRUE;
			printf("%s", sqlite3_errmsg(db));
			break;
		}
		sqlite3_reset(stmt);
	}

	if (bIsErr) {
		rc = sqlite3_exec(db, "rollback;", 0, 0, 0);
	} else {
		rc = sqlite3_exec(db, "commit;", 0, 0, 0);
	}

	if (sql_insert != NULL ) {
		sqlite3_free(sql_insert);
	}
	if (stmt != NULL ) {
		rc = sqlite3_finalize(stmt);
	}
	return rc;
}

/*TBL_CPPTOKENLIST*/
static INT insertCppTokenList(sqlite3 *db, AST tuIdx) {
	INT rc = 0;
	sqlite3_stmt * stmt;
	const char *zTail;
	PSZ sql_insert = NULL;
	BOOL bIsErr = FALSE;

	AST max = 0;
	AST i = 0;

	rc = sqlite3_exec(db, "begin;", 0, 0, 0);
	if (rc != SQLITE_OK) {
		return rc;
	}

	max = stCorePPTokenListAccess.getMax();

	sql_insert = sqlite3_mprintf("INSERT INTO %q VALUES(?,?,?,?,?,?);",
			TBL_CPPTOKENLIST);
	rc = sqlite3_prepare(db, sql_insert, -1, &stmt, &zTail);
	if (rc != SQLITE_OK || stmt == NULL ) {
		if (sql_insert != NULL ) {
			sqlite3_free(sql_insert);
		}
		if (stmt != NULL ) {
			sqlite3_finalize(stmt);
		}
		return COEXIT_ERROR;
	}

	for (i = 1; i <= max; i++) {

		sqlite3_bind_int(stmt, CPP_UNIT_INDEX, tuIdx);
		sqlite3_bind_int(stmt, CPP_TABLE_INDEX, i);

		sqlite3_bind_int(stmt, CPPTOKEN_CODE_SCOPE_INFO,
				stCorePPTokenListAccess.codeScope.get(i));

		sqlite3_bind_text(stmt, CPPTOKEN_TOKEN_LABEL,
				stCorePPTokenListAccess.name.get(i), -1, SQLITE_STATIC );

		sqlite3_bind_int(stmt, CPPTOKEN_MACRO_EXT,
				stCorePPTokenListAccess.macroExt.get(i));

		sqlite3_bind_int(stmt, CPPTOKEN_PPTOKEN_KIND,
				stCorePPTokenListAccess.ppTokenKind.get(i));

		rc = sqlite3_step(stmt);
		if (rc != SQLITE_DONE) {
			bIsErr = TRUE;
			printf("%s", sqlite3_errmsg(db));
			break;
		}
		sqlite3_reset(stmt);
	}

	if (bIsErr) {
		rc = sqlite3_exec(db, "rollback;", 0, 0, 0);
	} else {
		rc = sqlite3_exec(db, "commit;", 0, 0, 0);
	}

	if (sql_insert != NULL ) {
		sqlite3_free(sql_insert);
	}
	if (stmt != NULL ) {
		rc = sqlite3_finalize(stmt);
	}
	return rc;
}

/*insert cpp tables*/
INT DLL_EXPORT insertCppTables(sqlite3 *db, AST tuIdx) {
	INT rc = 0;

	rc = insertCppDirectiveInfo(db, tuIdx);
	if (rc != COEXIT_SUCCESS) {
		return rc;
	}

	rc = insertCppMacroDefInfo(db, tuIdx);
	if (rc != COEXIT_SUCCESS) {
		return rc;
	}

	rc = insertCppDefRepInfo(db, tuIdx);
	if (rc != COEXIT_SUCCESS) {
		return rc;
	}

	rc = insertCppPPCondition(db, tuIdx);
	if (rc != COEXIT_SUCCESS) {
		return rc;
	}

	rc = insertCppTokenList(db, tuIdx);
	if (rc != COEXIT_SUCCESS) {
		return rc;
	}

	return COEXIT_SUCCESS;
}
